#ifndef BEHAVIORGRIDSERVER_H
#define BEHAVIORGRIDSERVER_H

#include <boost/asio.hpp>
#include <boost/cstdint.hpp>
#include <BehaviorHandler.h>
#include  <MasterTask.h>
#include <GridPackedMessage.h>
#include "NewGridConnectionManager.h"
#include "gridprotocol.pb.h"
#include <TaskResult.h>
#include <Log.h>
#include <vector>
#include <string>
#include <Utils.h>

using namespace std;
using namespace Network;
using namespace MasterWorkerFramework;
using boost::uint8_t;

namespace gPt = gridprotocol;

class BehaviorGridServer : public BehaviorHandler<gridprotocol::Request,gridprotocol::Response>
{
public:
	
		BehaviorGridServer()
			:BehaviorHandler(){
		};

		~BehaviorGridServer(){};

		gridprotocol::Request* NewRequestMessage()
		{
			gridprotocol::Request* msg = new gridprotocol::Request();
			return msg;
		}

		boost::shared_ptr<gridprotocol::Request> NewRequestSharedPtr()
		{
			return boost::shared_ptr<gridprotocol::Request>(NewRequestMessage());
		}

		boost::shared_ptr<gridprotocol::Response> NewResponseSharedPtr()
		{
			return boost::shared_ptr<gridprotocol::Response>(NewResponseMessage());
		}

		gridprotocol::Response* NewResponseMessage()
		{
			gridprotocol::Response* msg = new gridprotocol::Response();
			return msg;
		}

	void SetMaster(GridMasterTask* master)
	{
		masterTask_ =master;
		masterTask_->Build();
	}

	NewGridConnectionManager<gridprotocol::Request,gridprotocol::Response>* connectionManager_;

	void SetKillSwitch(bool isKill)
	{
		return;
	}
	
	bool GetKillSwitch()
	{
		return false;
	}

	

	void ExecuteMaster(NewGridConnectionManager<gridprotocol::Request,gridprotocol::Response>* connectionManager)
	{
		connectionManager_ =connectionManager;

		if (NULL!=masterTask_)
		{
			std::vector<AbstractGridSlaveTask*>* batch = new std::vector<AbstractGridSlaveTask*>();
			std::vector<gridprotocol::Request*>* r_messages= new std::vector<gridprotocol::Request*>();

			batch =masterTask_->GetBach();

			for (std::vector<AbstractGridSlaveTask*>::iterator vi = batch->begin(); vi != batch->end(); vi++)
			 {
					gridprotocol::Request* request = new gridprotocol::Request();
					request->set_type(gridprotocol::Request::ASK_TASK);
					gridprotocol::Request_RequestAskTask* r = request->mutable_request_ask_task();

					for (std::vector<TaskResult*>::iterator vi2 = (*vi)->GetBindedResult()->begin(); vi2 != (*vi)->GetBindedResult()->end(); vi2++)
					{
						gridprotocol::Param* p = r->add_param();
						
						switch ((*vi2)->GetType())
						{
							case VALUE_TYPE::VALUE_TYPE_FLOAT:
								gridprotocol::Param_ParamFloat* p_float;
								p->set_type(gPt::Param::TYPE_FLOAT);
								p_float = p->mutable_request_param_float();
								p_float->set_value(*((*vi2)->GetResult<float>()));
								break;
							case VALUE_TYPE::VALUE_TYPE_INT32:
								gridprotocol::Param_ParamInt32* p_int;
								p->set_type(gPt::Param::TYPE_INT32);
								p_int = p->mutable_request_param_int32();
								p_int->set_value(*((*vi2)->GetResult<int>()));
								break;
							case VALUE_TYPE::VALUE_TYPE_STRING:
								gridprotocol::Param_ParamString* p_string;
								p->set_type(gPt::Param::TYPE_STRING);
								p_string = p->mutable_request_param_string();
								p_string->set_value(*((*vi2)->GetResult<std::string>()));
								break;
						}
					}

					r->set_t_name(*(*vi)->GetSlaveTaskName());
					r->set_t_id(*(*vi)->GetHash());
					r_messages->push_back(request);
			 }

			for (std::vector<gridprotocol::Request*>::iterator vi = r_messages->begin(); vi != r_messages->end(); vi++)
			 {
				 connectionManager_->ExecuteTask((*vi),(*vi)->mutable_request_ask_task()->mutable_t_id());
			 }

		}
	}

	void HandleResponse(gridprotocol::Response &response,gridprotocol::Request &request,  void* args)
	{
		std::vector<uint8_t> writebuf;
		long r;
		switch (response.type())
		{
		case gPt::Response::ACK_AVAIL:
				request.set_type (gPt::Request::ASK_ID);
				request.mutable_request_ask_id();
				break;
		case  gPt::Response::ACK_ID:				
			{
				request.set_type (gPt::Request::ASK_DIE);
				request.mutable_request_ask_die();
				break;
			}
		case gPt::Response::ACK_RESULT:
			{
				gPt::Response_ResponseAckResult result = response.response_ack_result();

				std::string* task_hash = result.mutable_t_id();
				AbstractGridSlaveTask* task = masterTask_->GetTask(task_hash);

				TaskResult* t_result;

					if (response.response_ack_result().results(0).type() == gPt::Param::TYPE_INT32)
					{
						t_result = new TaskResult(VALUE_TYPE::VALUE_TYPE_INT32);
						int r = response.response_ack_result().results(0).request_param_int32().value();
						int* r_ptr= new int(r);
						t_result->SetResult<int>(r_ptr);
					}

					else if (response.response_ack_result().results(0).type() == gPt::Param::TYPE_FLOAT)
					{
						t_result = new TaskResult(VALUE_TYPE::VALUE_TYPE_FLOAT);
						float r = response.response_ack_result().results(0).request_param_float().value();
						float* r_ptr= new float(r);
						t_result->SetResult<float>(r_ptr);
					}

					else if(response.response_ack_result().results(0).type() == gPt::Param::TYPE_STRING)
					{
						t_result = new TaskResult(VALUE_TYPE::VALUE_TYPE_STRING);
						string r = response.response_ack_result().results(0).request_param_string().value();
						string* r_ptr = new string(r);
						t_result->SetResult<string>(r_ptr);
					}

					task->SetResult(t_result);
					task->Join();
					
					connectionManager_->UpdateSentTaskList(*task_hash);
					ExecuteMaster(connectionManager_);

				request.set_type (gPt::Request::ASK_DIE);
				request.mutable_request_ask_die();
				break;
			}
			default:
				break;
		}

		
		}
		void HandleRequest (gridprotocol::Response &response, gridprotocol::Request &request, void* args)
		{
			return;
		}
		private:
			GridMasterTask* masterTask_;
			

};

#endif